﻿
package extremefx.ui {
	import extremefx.IEnumerator;
	import extremefx.data.DSItem;
	import extremefx.data.DataSource;
	import extremefx.events.EventHandler;
	import extremefx.geom.Size;
	
	import flash.geom.Point;	

	/**
	 * @author Marcelo Volmaro
	 */
	public final class RadioGroup extends Container {
		private static var _groups:Array = [];

		private var _radios:Vector.<Radio>;
		private var _selected:Radio;
		private var _dataSource:DataSource;
		private var _params:UIParameters;
		
		public var columns:uint;
		public var hMargin:uint;
		public var vMargin:uint;
		
		public function RadioGroup(pParameters:UIParameters = null) {
			super();
			
			_radios = new Vector.<Radio>();
			_groups[_name] = this;
			_params = pParameters;
			_kind = "RadioGroup";
			columns = 2;
			hMargin = vMargin = 4;
		}
		
		public function setDataSource(pDataSource:DataSource):void{
			_dataSource = pDataSource;
			
			for each(var r:Radio in _radios){
				r.dispose();
			}
			
			_refreshRadios();
		}
		
		override public function set parent(pParent:Container):void {
			super.parent = pParent;
			_refreshRadios();
		}
		
		private function _refreshRadios():void {
			//it is impossible to have a radiogroup with one radio only...
			if (!_parent || _dataSource == null || _dataSource.count < 2) return;
			
			var m:Vector.<Radio> = new Vector.<Radio>(),
			e:IEnumerator = _dataSource.getEnumerator(),
			c:Boolean = true,
			r:Radio,
			item:DSItem;
			
			while (e.moveNext()){
				item = e.current as DSItem;
				r = new Radio(item.text, item.value, _params);
				r._group = this;
				add(r);
				
				if (c) {//select the first one by default.
					r.selected = true;
					_selected = r;
					c = false;
				}
				
				m.push(r);
			}
			
			_radios = m;
			_calcHeight();
			invalidate();
		}
		
		internal function _selectNext(pDir:int):void {
			var idx:int = _radios.indexOf(_selected);
			
			if (_selected) {
				_selected.blur(); 
			}
			
			var r:Radio = _selected = _getItem(idx, pDir, 0);
			if (r) r.tabFocus = true;
		}
		
		private function _getItem(pIndex:int, pDirection:int, pCounter:int):Radio {
			var l:int = _radios.length;
			if (l <= 1) return _radios[0];

			pIndex += pDirection;
			
			if (pIndex < 0) {
				pIndex = l-1;
				
			} else if (pIndex >= l) pIndex = 0;
			
			if (pCounter == l) return null;
			
			var ns:Radio = _radios[pIndex];
			
			if (ns.enabled){
				return ns;
							
			} else {
				return _getItem(pIndex, pDirection, ++pCounter);
			}
		}
		
		internal function select(pRadio:Radio, pValue:Boolean):void{
			if (!pValue) return;
			
			for each(var r:Radio in _radios){
				if (r.selected && r != pRadio) {
					r.selected = false;
					break;
				}
			}
			
			_selected = pRadio;
			if (_eOnChange) _eOnChange.fire(pRadio._value);
		}
		
		public function get selectedIndex():uint {
			return _radios.indexOf(_selected);
		}
		
		public function set selectedIndex(pIndex:uint):void {
			if (pIndex > _radios.length) pIndex = 0;
			select(_radios[pIndex], true);
		}
		
		public function get selectedValue():*{
			return _selected._value;
		}
		
		public function set selectedValue(pValue:*):void{
			for each(var r:Radio in _radios){
				if (r._value != pValue) continue;
				
				r.selected = true;
				break;
			}
		}
		
		override protected function _draw():void {
			if (_radios.length < 1) return;
			
			var c:uint = columns;
			if (c < 1) c = 1;
			if (c > 20) c = 20;
			
			var cmpW:uint = Math.floor(_parent.width / c) - hMargin,
			rh:uint = _radios[0].height,
			startX:int = 0,
			startY:int = 0,
			actCol:uint = 0;
			
			var p:Point = new Point();
	
			for each (var r:Radio in _radios){
				p.x = startX;
				p.y = startY;
				
				r.position = p;
				++actCol;
				
				if (actCol == c){//wrap
					startX = actCol = 0;
					startY += rh + vMargin;
					
				} else {
					startX += cmpW; 
				}
			}
		}
		
		private function _calcHeight():void {
			if (!_parent || !_radios.length) return;
			
			var c:uint = columns;
			if (c < 1) c = 1;
			if (c > 20) c = 20;
			
			var cmpW:uint = Math.floor(_parent.width / c) - hMargin,
			rh:uint = _radios[0].height,
			startX:int = 0,
			startY:int = 0,
			actCol:uint = 0, 
			l:uint = _radios.length,
			i:uint = 0;
			
			while (i < l){
				++i;
				++actCol;

				if (actCol == c){//wrap
					startX = 0;
					startY += rh + vMargin;
					
				} else {
					startX += cmpW; 
				}
			}
			
			_height = startY + rh;
		}
		
		override public function get preferredSize():Size {
			var c:uint = columns;
			if (c < 1) c = 1;
			if (c > 20) c = 20;
			
			var rh:uint = _radios[0].height,
			startY:int = 0,
			actCol:uint = 0,
			maxWidth:uint = 0;
			
			for each (var r:Radio in _radios){
				++actCol;
				maxWidth = Math.max(maxWidth, r.preferredSize.width);
				
				if (actCol == c){//wrap
					startY += rh + vMargin;
				}
			}
			
			return new Size((maxWidth * c)+(hMargin * (c-1)), startY + rh);
		}
		
		override public function get minimumSize():Size {
			return preferredSize;
		}
		
		override public function dispose():void {
			if (_disposing) return;
			super.dispose();
			
			for each(var r:Radio in _radios){
				r.dispose();
			}
			
			_eOnChange.dispose();
		}
		
		private var _eOnChange:EventHandler;
		public function get onChange():EventHandler{
			if (_eOnChange == null) _eOnChange = new EventHandler(this);
			return _eOnChange;
		}
	}
}
